package com.yu.crm.service.impl;

import cn.hutool.core.io.IoUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.yu.crm.domain.pojo.CrmLogin;
import com.yu.crm.domain.pojo.CrmUser;
import com.yu.crm.mapper.CrmLoginMapper;
import com.yu.crm.service.CrmLoginService;
import com.yu.crm.service.CrmMenuService;
import com.yu.crm.service.CrmUserService;
import com.yxzz.common.BaseResponse;
import com.yxzz.common.config.UserCacheManager;
import com.yxzz.common.domain.entity.TokenUser;
import com.yxzz.common.exception.GeneralException;
import com.yxzz.common.helper.*;
import com.yxzz.common.helper.valid.ValidatorHelpers;
import com.yxzz.common.sms.HycSmsUtil;
import com.yxzz.common.utils.Alimessage;
import com.yxzz.common.utils.MD5Utils;
import lombok.extern.log4j.Log4j2;
import org.apache.commons.codec.digest.Md5Crypt;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.imageio.ImageIO;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * 模块名称：
 * 功能说明：
 *
 * @Author: bin-donnie
 * @Date: 2019-07-30 09:24
 */


@Service
@Log4j2
@Transactional(rollbackFor = Exception.class)
public class CrmLoginServiceImpl extends ServiceImpl<CrmLoginMapper, CrmLogin> implements CrmLoginService {
    private final Logger logger = LoggerFactory.getLogger(this.getClass());

    @Autowired
    CrmUserService userService;
    @Autowired
    CrmMenuService crmMenuService;

    @Autowired
    UserCacheManager userCacheManager;

    @Override
    public void registry(CrmLogin entity) {
        entity.setId(null);
        //entity.setUserId(IDHelper.getIncreaseIdByCurrentTimeMillis());
        if (entity.getLoginType() == 1 && DataHelpers.isNotEmpty(entity.getLoginName()) && DataHelpers.isNotEmpty(entity.getLoginPassword())) {
            if (DataHelpers.isNotEmpty(entity.getLoginExtraCode())) {
                if (!this.verifyImageCode(entity.getVerifyCodeId(), entity.getLoginExtraCode())) {
                    ExceptionHelpers.throwGeneralException("图片验证码错误");
                }
            } else {
                ExceptionHelpers.throwGeneralException("图片验证码不能为空");
            }
            LambdaQueryWrapper<CrmUser> lambdaQueryWrapper = new LambdaQueryWrapper<>();
            lambdaQueryWrapper.eq(CrmUser::getUserAccountId, entity.getLoginName());
            int oldCount = userService.count(lambdaQueryWrapper);
            ValidatorHelpers.validateDataExist("用户名已存在", oldCount);
            //账号密码注册
            CrmUser user = new CrmUser();
            user.setUserId(IDHelper.getIncreaseIdByCurrentTimeMillis());
            user.setUserAccountId(entity.getLoginName());
            user.setUserAccountPwd(entity.getLoginPassword());
            user.setGmtCreate(DateHelpers.now());
            ExceptionHelpers.checkData(userService.save(user), "注册失败");
        } else if (entity.getLoginType() == 2 && DataHelpers.isNotEmpty(entity.getLoginName()) && DataHelpers.isNotEmpty(entity.getLoginPassword())) {
            if (!ValidHelpers.isMobile(entity.getLoginName())) {
                ExceptionHelpers.throwGeneralException("手机号码格式不正确");
            }
            this.isExistPhone(entity.getLoginName());
            //手机号注册
            if (this.verifySmsCode(entity.getLoginName(), entity.getLoginExtraCode())) {
                CrmUser user = new CrmUser();
                user.setUserId(IDHelper.getIncreaseIdByCurrentTimeMillis());
                user.setUserPhone(entity.getLoginName());
                user.setUserAccountPwd(entity.getLoginPassword());
                user.setGmtCreate(DateHelpers.now());
                ExceptionHelpers.checkData(userService.save(user), "注册失败");
            } else {
                ExceptionHelpers.throwGeneralException("手机验证码不正确");
            }
        } else {
            ExceptionHelpers.throwGeneralException("注册失败，信息不完整");
        }
    }

    @Override
    public CrmUser login(CrmLogin entity) {
        if (entity.getLoginType() == 1 && DataHelpers.isNotEmpty(entity.getLoginName()) && DataHelpers.isNotEmpty(entity.getLoginPassword())) {
            //账号密码登录
//            if (DataHelpers.isNotEmpty(entity.getLoginExtraCode())) {
//                if (!this.verifyImageCode(entity.getVerifyCodeId(), entity.getLoginExtraCode())) {
//                    ExceptionHelpers.throwGeneralException("图片验证码错误");
//                }
//            } else {
//                ExceptionHelpers.throwGeneralException("图片验证码不能为空");
//            }
            LambdaQueryWrapper<CrmUser> lambdaQueryWrapper = new LambdaQueryWrapper<>();
            lambdaQueryWrapper.and(x->x.eq(CrmUser::getUserName, entity.getLoginName()).or().eq(CrmUser::getUserPhone,
                    entity.getLoginName()));
            lambdaQueryWrapper.eq(CrmUser::getUserAccountPwd, MD5Utils.MD5Encode(entity.getLoginPassword()));
            CrmUser user = userService.getOne(lambdaQueryWrapper);
            ExceptionHelpers.checkData(user, "登录失败，用户名或密码错误");
            String loginToken = TokenHelpers.generateTokenString(user.getUserId());
            user.setLoginToken(loginToken);
            TokenUser tokenUser = new TokenUser();
            tokenUser.setToken(user.getLoginToken());
            tokenUser.setUserId(user.getUserId());
            tokenUser.setUserName(user.getUserName());
            userCacheManager.save(loginToken, tokenUser, 604800L); //7天有效

            List<HashMap<String, Object>> menusByUserId = crmMenuService.getMenusByUserId(user.getUserId());
            if(DataHelpers.isNotEmpty(menusByUserId)){
                user.setRoles(menusByUserId);
            }

            //判断是否在线
            isLogin(entity, loginToken);

            return user;
        }
        else if (entity.getLoginType() == 2 && DataHelpers.isNotEmpty(entity.getLoginName())) {
            //短信验证码登录
            LambdaQueryWrapper<CrmUser> lambdaQueryWrapper = new LambdaQueryWrapper<>();
            lambdaQueryWrapper.eq(CrmUser::getUserPhone, entity.getLoginName());
            CrmUser user = userService.getOne(lambdaQueryWrapper);
            ExceptionHelpers.checkData(user, "该用户不存在");
            if (this.verifySmsCode(entity.getLoginName(), entity.getLoginPassword())) {
                String loginToken = TokenHelpers.generateTokenString(user.getUserId());
                user.setLoginToken(loginToken);
                TokenUser tokenUser = new TokenUser();
                tokenUser.setToken(user.getLoginToken());
                tokenUser.setUserId(user.getUserId());
                tokenUser.setUserName(user.getUserName());
                userCacheManager.save(loginToken, tokenUser, 604800L);

                List<HashMap<String, Object>> menusByUserId = crmMenuService.getMenusByUserId(user.getUserId());
                if(DataHelpers.isNotEmpty(menusByUserId)){
                    user.setRoles(menusByUserId);
                }
                //判断是否在线
                isLogin(entity, loginToken);

                return user;
            } else {
                ExceptionHelpers.throwGeneralException("手机验证码不正确");
            }
        }
        else {
            ExceptionHelpers.throwGeneralException("登录失败，信息不完整");
        }
        return null;
    }

    /**
     * 判断是否账号同时在线
     * @param entity
     * @param loginToken
     */
    private void isLogin(CrmLogin entity, String loginToken) {
        QueryWrapper<CrmLogin> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("login_name", entity.getLoginName());
        List<CrmLogin> crmLogins = baseMapper.selectList(queryWrapper);
        if (DataHelpers.isNotEmpty(crmLogins)) {
            int i = 1;
            for (CrmLogin crmLogin : crmLogins) {
                //获取同时登陆人数
                Integer loginCount = Integer.parseInt(ResourceConfigHelpers.getProperty("login.count"));
                if (DataHelpers.isNotEmpty(crmLogin.getUserToken()) && crmLogins.size() >= loginCount) {
                    if (i >= loginCount) {
                        userCacheManager.delete(crmLogin.getUserToken());
                        baseMapper.deleteById(crmLogin.getId());
                    } else {
                        break;
                    }
                    i++;
                }
            }
        }

        //添加流水记录
        entity.setUserToken(loginToken);
        entity.setGmtCreate(LocalDateTime.now());
        baseMapper.insert(entity);
    }

    @Override
    public void logout(String loginToken) {
        if (userCacheManager.validate(loginToken)) {
            userCacheManager.delete(loginToken);
        }
    }

    @Override
    public BaseResponse<Boolean> isExistPhone(String phone) {
        LambdaQueryWrapper<CrmUser> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.eq(CrmUser::getUserPhone, phone);
        int oldCount = userService.count(lambdaQueryWrapper);
        if (oldCount > 0) {
            return BaseResponse.success(true, "该手机号已注册");
        } else {
            return BaseResponse.success(false, "该手机号未注册");
        }
    }

    @Override
    public void requestImageCode(HttpServletRequest request, HttpServletResponse response) {
        String tempID = IDHelper.getRandomIdByUUID();
        Map<String, Object> resultMap = RandomValidateCodeUtil.getRandomCode(request, response);
        //Map<String, String> tempMap = new HashMap<>();
        //tempMap.put("code", String.valueOf(resultMap.get("code")));
        String key = "code:" + tempID;
        log.info("save image verify, key = {}, code = {}", key, resultMap.get("code"));
        if (RedisHelpers.set(key, String.valueOf(resultMap.get("code")), 300L)) {
            try {
                //设置相应类型,告诉浏览器输出的内容为图片
                response.setContentType("image/jpeg");
                //设置响应头信息，告诉浏览器不要缓存此内容
                response.setHeader("Pragma", "No-cache");
                response.setHeader("Cache-Control", "no-cache");
                response.setDateHeader("Expire", 0);
                response.setHeader("Id", tempID);
                ImageIO.write((BufferedImage) resultMap.get("image"), "JPEG", response.getOutputStream());
            } catch (IOException e) {
                e.printStackTrace();
                ExceptionHelpers.throwGeneralException("生成验证码图片失败");
            }
        } else {
            ExceptionHelpers.throwGeneralException("生成验证码图片缓存失败");
        }
    }

    @Override
    public Boolean verifyImageCode(String verifyId, String code) {
        String key = "code:" + verifyId;
        if (RedisHelpers.hasKey(key)) {
            if (RedisHelpers.get(key).equals(code)) {
                return true;
            }
        }
        ExceptionHelpers.throwGeneralException("图片验证码验证失败");
        return false;
    }

    /**
     * 通过手机号发送验证码
     * @param phone
     * @return
     */
    @Override
    public Boolean requestSmsCode(String phone) {
        //HycSmsUtil.requestCode(phone);
        if(DataHelpers.isNotEmptyString(phone)){
            QueryWrapper<CrmUser> queryWrapper = new QueryWrapper<>();
            queryWrapper.eq("user_phone",phone);
            queryWrapper.eq("is_deleted",0);
            List<CrmUser> list = userService.list(queryWrapper);
            if (DataHelpers.isEmpty(list) || list.size() == 0) {
                throw new GeneralException("该手机号暂不支持此功能");
            }

            //发送间隔判断
            Boolean aBoolean = RedisHelpers.hasKey("AliCode:"+phone);
            if (aBoolean) {
                throw new GeneralException("验证码已发送至您的手机,1分钟之内请勿重复获取");
            }
            //生成验证码
            String code=getMessageCodes(phone);
            //发送验证码
            Alimessage.sendSmsUserType(phone,code,
                    ResourceConfigHelpers.getProperty("Alimessage.accessKeyId"),
                    ResourceConfigHelpers.getProperty("Alimessage.accessKeySecret"),
                    //ResourceConfigHelpers.getProperty("Alimessage.signName"),
                    "中智平台",
                    ResourceConfigHelpers.getProperty("Alimessage.templateCode"));
            logger.info("成功-获取短信验证码-结果========phone》》"+phone+"======code》》"+code);
            return true;
        }else{
            throw new GeneralException("请输入手机号");
        }
    }

    @Override
    public boolean verifySmsCode(String phone, String code) {
        Boolean aBoolean = RedisHelpers.hasKey("AliCode:"+phone);
        if (aBoolean) {
            //获取redis对应code
            String redisCode = RedisHelpers.get("AliCode:" + phone).toString();
            if (redisCode.equals(code)){
                return true;
            }
        }else{
            throw new GeneralException("验证码已失效,请重新获取");
        }
        return false;
        //return HycSmsUtil.checkCode(phone, code);
    }

    /**
     * 生成验证码(有效期五分钟)
     *
     * @return
     * @throws Exception
     */
    public String getMessageCodes(String phone)  {
        //六位数验证码
        int randNum = (int) ((Math.random() * 9 + 1) * 100000);
        String s = String.valueOf(randNum);
        try {
            //删除原有验证码
            RedisHelpers.delete("AliCode:"+phone );
            //设置验证码信息
            RedisHelpers.set("AliCode:"+phone, s);
            //设置过期时间
            RedisHelpers.expire("AliCode:"+phone, 300);
        } catch (Exception e) {
            e.printStackTrace();
            logger.error(e.getMessage());
            throw new GeneralException("生成验证码失败");
        }
        return s;
    }
}
